package lia.util;

import static lia.util.Constants.*;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * utilities for lia
 * 
 * @author Wenlong Meng(wenlong.meng@gmail.com)
 * @version 1.0 at 2011/08/03
 * @version 1.1 at 2011/08/06 update by F.H Dragon for add public static IndexConfig buildIndexConfig(FileReaderConfig frc)
 */
public class Utilities {
	
	// local variables
	/**
	 * log
	 */
	private static final Logger logger = Logger.getLogger("commonLogger");
	
	/**
	 * build index dir
	 * 
	 * @param chapterNum
	 * @return
	 * @throws IllegalArgumentException if flag is empty
	 */
	public static String buildIndexDir(String chapterNum){
		//empty:throw Exception
		if(chapterNum == null || chapterNum.trim().length() == 0){
			throw new IllegalArgumentException("flag is not empty.");
		}
		return String.format(LIA_INDEX_DIR, chapterNum);
	}
	
	/**
	 * build data dir
	 * 
	 * @param flag
	 * @return
	 */
	public static String buildDataDir(String chapterNum){
		//empty:throw Exception
		if(chapterNum == null || chapterNum.trim().length() == 0){
			throw new IllegalArgumentException("flag is not empty.");
		}
		return String.format(LIA_DATA_DIR, chapterNum);
	}
	
	/**
	 * build index config
	 * 
	 * @param frc the config of index config file 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static IndexConfig buildIndexConfig(FileReaderConfig frc){
		
		IndexConfig ic = new IndexConfig();
		try {
			SAXReader saxreader = new SAXReader();
			Element root = saxreader.read(new File(frc.getPath())).getRootElement();
			ic.setName(root.elementText("name"));
			ic.setComment(root.elementText("comment"));
			List<Element> documents = root.elements("document");
			for(Element document : documents){
				IndexConfig.DocumentConfig icdc = new IndexConfig.DocumentConfig();
				icdc.setName(document.elementText("name"));
				icdc.setComment(document.elementText("comment"));
				List<Element> files = document.elements("field");
				for(Element file : files){
					IndexConfig.FieldConfig icfc = new IndexConfig.FieldConfig();
					icfc.setName(file.elementText("name"));
					icfc.setComment(file.elementText("comment"));
					String fieldStore = file.elementText("Field.Store");
					icfc.setStore(CONFIG_FIELD_STORES.get(fieldStore == null ? "YES" : fieldStore));
					String fieldIndex = file.elementText("Field.Index");
					icfc.setIndex(CONFIG_FIELD_INDEXS.get(fieldIndex == null ? "YES" : fieldIndex));
					String fieldTermVector = file.elementText("Field.TermVector");
					icfc.setTermVector(CONFIG_FIELD_TERMVECTORS.get(fieldTermVector == null ? "NO" : fieldTermVector));
					icdc.setField(icfc);
				}
				ic.setDoc(icdc);
			}
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
		
		return ic;
	}
	
	/**
	 * get data from path
	 * 
	 * @param path file path
	 * @return the data of the file 
	 * 		   null, if file is not exists, or exception in read file
	 * @throws IOException 
	 * @throws DocumentException 
	 */
	public static List<Map<String, String>> getData(FileReaderConfig frc) throws IOException, DocumentException{
		
		//xml file handle
		if(frc.getFileType() == FileReaderConfig.FileType.xml){
			return getDataFromXml(frc);
		//txt file handle
		}else if(frc.getFileType() == FileReaderConfig.FileType.txt){
			return getDataFromTxt(frc);
		//unsupported file 
		}else{
			throw new UnsupportedOperationException("unsupport this type file.");
		}
	}
	
	/**
	 * get data from txt path
	 * 
	 * @param frc the option of read file 
	 * @return
	 * @throws IOException 
	 */
	public static List<Map<String, String>> getDataFromTxt(FileReaderConfig frc) throws IOException {
		
		String path = frc.getPath();
		File file=new File(path);
		if(!file.exists()||file.isDirectory()){
			throw new FileNotFoundException("the file(" + path + ") is not exists. or it is directory.");
		}
		
		BufferedReader br = new BufferedReader(new FileReader(file));
		String line = null;
		List<Map<String, String>> ds = new ArrayList<Map<String, String>>();
		//read keys: the first line
		String[] ks = null; 
		if((line = br.readLine()) != null){
			ks = line.split(frc.getFieldSeparator());
		}
		//read data
		String[] fields = null;
		while((line = br.readLine()) != null){
			fields = line.split(frc.getFieldSeparator());
			Map<String, String> d = new HashMap<String, String>();
			for(int i = 0, counti = ks.length; i < counti; i++){
				d.put(ks[i], fields[i]);
			}
			ds.add(d);
		}

		return ds;
	}

	/**
	 * get data from xml path TODO: continue
	 * 
	 * @param frc the option of read file 
	 * @return
	 * @throws FileNotFoundException 
	 * @throws DocumentException 
	 */
	public static List<Map<String, String>> getDataFromXml(FileReaderConfig frc) throws FileNotFoundException, DocumentException{
		
		String path = frc.getPath();
		File file=new File(path);
		if(!file.exists()||file.isDirectory()){
			throw new FileNotFoundException("the file(" + path + ") is not exists. or it is directory.");
		}
		
		SAXReader saxreader = new SAXReader();
        Document document = (Document)saxreader.read(file);
        @SuppressWarnings("unused")
        Element root = document.getRootElement();
        List<Map<String, String>> ds = new ArrayList<Map<String, String>>();
        
        return ds;
	}

	/**
	 * test include title
	 * 
	 * @param is
	 * @param hits
	 * @param Title
	 * @return
	 * @throws IOException 
	 * @throws CorruptIndexException 
	 */
	public static boolean hitsIncludeTitle(IndexSearcher is, TopDocs hits, String title) throws CorruptIndexException, IOException{
		for(ScoreDoc scoreDoc : hits.scoreDocs){
			org.apache.lucene.document.Document doc = is.doc(scoreDoc.doc);
			if(title.equalsIgnoreCase(doc.get("title"))){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * log documents
	 * 
	 * @param is indexSearcher
	 * @param docs topDocs
	 * @return
	 * @throws IOException 
	 * @throws CorruptIndexException 
	 */
	public static void logDocs(IndexSearcher is, TopDocs topDocs) throws CorruptIndexException, IOException{
		for(ScoreDoc scoreDoc : topDocs.scoreDocs){
			logger.debug("score=" + scoreDoc.score + ", " + is.doc(scoreDoc.doc));
		}
	}
	
	/**
	 * test...
	 * 
	 * @param args
	 * @throws IOException
	 * @throws DocumentException
	 */
	public static void main(String[] args) throws IOException, DocumentException{
		FileReaderConfig frc = new FileReaderConfig(buildDataDir("2") + "/test1.txt");
		frc.setFieldSeparator("#");
		List<Map<String, String>> ds = getData(frc);
		System.out.println(ds);
		frc = new FileReaderConfig(LIA_CONFIG_PATH);
		IndexConfig ic = buildIndexConfig(frc);
		System.out.println(ic);
		System.out.println(ic.document("chapter201"));
		System.out.println(ic.document("chapter201").field("id"));
		
	}

}
